#include <locale.h>
#include <stdio.h>
#include <stdint.h>
#include <Windows.h>
#include <process.h>
#include <assert.h>
#include <TCHAR.h>
#include <time.h>

// simulate mcu functions ---------------------------------------------------------------------------------
#include "CH58x_common.h"
#include "simu_mcu582.h"

static const char* zy_m0_eeprom = ".\\app\\zy_m0_eeprom.dat";
static const char* zy_m0_flash = ".\\app\\zy_m0_flash.dat";
char* simu_uart0_str = (char*)_T("\\\\.\\COM30");
char* simu_uart1_str = (char*)_T("\\\\.\\COM32");
char* simu_uart2_str = (char*)_T("\\\\.\\COM34");

void __WFE(void) {};
void DelayUs(int x) {};
void PWR_PeriphWakeUpCfg(FunctionalState s, uint8_t perph, WakeUP_ModeypeDef mode) {};

void SetSysClock(int x) { return; }
void DelayMs(int x) { Sleep(x); }
void LClk32K_Select(int x) { return; }
void RTC_TMRFunCfg(int x) { return; }
void PFIC_EnableIRQ(int x) { return; }
void SYS_RecoverIrq(uint32_t irq_status) { return; }
void WWDG_ResetCfg(int x) { ; }
void HSECFG_Current(int x) { ; }
void ADC_ExtSingleChSampInit(ADC_SampClkTypeDef sp, ADC_SignalPGATypeDef ga) { ; }
signed short ADC_DataCalib_Rough(void) { return 0; } // 采样数据粗调,获取偏差值
uint8_t RTC_GetITFlag(RTC_EVENTTypeDef f) { return 1; }
void Calibration_LSI(int x) { ; }
int GetSysClock(void) { return 0; }

void SYS_DisableAllIrq(uint32_t* pirqv) { ; } // 关中断。
void SYS_ResetExecute(void) { ; }  //软件复位MCU

void WWDG_ITCfg(FunctionalState s){};
uint32_t FLASH_EEPROM_CMD(uint8_t cmd, uint32_t StartAddr, void* Buffer, uint32_t Length){};
void sys_safe_access_enable(void){};
void sys_safe_access_disable(void) {};
void TMR0_TimerInit(uint32_t t) {};
void PFIC_DisableIRQ(IRQn_Type IRQn) {};


SimuHWData simu_hw;         // 模拟硬件数据, 由模拟器周期下发
unsigned char simu_register[128] = { 0 };

void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode) 
{
    switch (mode)
    {
    case GPIO_ModeIN_Floating:
    case GPIO_ModeIN_PU:
    case GPIO_ModeIN_PD:
        simu_hw.gpioa_d &= ~pin;
        break;
    case GPIO_ModeOut_PP_5mA:
    case GPIO_ModeOut_PP_20mA:
        //simu_hw.gpioa_pd &= ~pin;
        simu_hw.gpioa_d |= pin;
        break;
    default:
        break;
    }
}
void GPIOB_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
{
    switch (mode)
    {
    case GPIO_ModeIN_Floating:
    case GPIO_ModeIN_PU:
    case GPIO_ModeIN_PD:
        simu_hw.gpiob_d &= ~pin;
        break;
    case GPIO_ModeOut_PP_5mA:
    case GPIO_ModeOut_PP_20mA:
        //simu_hw.gpioa_pd &= ~pin;
        simu_hw.gpiob_d |= pin;
        break;
    default:
        break;
    }
}
void GPIOA_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode) { ; }
void GPIOB_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode) { ; }
void GPIOPinRemap(int x, int y) { ; }
void GPIOA_ClearITFlagBit(int x) { ; }
void GPIOB_ClearITFlagBit(int x) { ; }
void RTC_ClearITFlag(RTC_EVENTTypeDef f) { ; }

uint16_t GPIOA_ReadITFlagPort(void) { return (uint16_t)simu_hw.gpioa; } // 用IO值模拟替代IO中断标志 
uint16_t GPIOB_ReadITFlagPort(void) { return (uint16_t)simu_hw.gpiob; } // 用IO值模拟替代IO中断标志 


// 
void DllPrintf(char* fmt, ...)
{
    //不定参数格式化
    va_list argptr;
    va_start(argptr, fmt);
    char buffer[512] = { 0 };
    //char *p = va_arg(argptr, char*);
    int cnt = vsprintf(buffer, fmt, argptr);
    va_end(argptr);
    //sprintf(buffer, "[%s:%u-%s]: xxxx\r\n", __FILE__, __LINE__, __FUNCTION__);

    //建立控制台窗口
    static HANDLE gHConsole = INVALID_HANDLE_VALUE;
    if (INVALID_HANDLE_VALUE == gHConsole) {
        //AllocConsole();
        gHConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    }
    //打印到指定的控制台窗口
    DWORD dw;
    //WriteConsole(gHConsole, buffer, strlen(buffer), &dw, NULL);
    WriteConsoleA(gHConsole, buffer, strlen(buffer), &dw, NULL);

    return;
}

// simu eeprom read/write
static uint8_t simu582_eeprom_data[32 * 1024] = { 0 };  // 32K
static simu_eeprom(void)
{
    FILE* fp = NULL;
    static int flag = 0;
    if (!flag) {
        fp = fopen(zy_m0_eeprom, "rb");
        if (fp != NULL) {
            fread(simu582_eeprom_data, 1, 32 * 1024, fp);
        }
        else {
            _mkdir(".\\app");
            fp = fopen(zy_m0_eeprom, "wb+");
            fwrite(simu582_eeprom_data, 1, 32 * 1024, fp);
        }       
    }
    if (fp) {
        fclose(fp);
        flag = 1;
    }
}
void EEPROM_READ(uint32_t StartAddr, uint8_t* Buffer, int Length)
{
    simu_eeprom();
    assert((StartAddr % 4) == 0);
    memcpy(Buffer, simu582_eeprom_data + StartAddr, Length);
}
void EEPROM_ERASE(uint32_t StartAddr, int Length)
{
    simu_eeprom();
    assert((StartAddr % 4) == 0);
    memset(simu582_eeprom_data + StartAddr, 0xff, Length);
    FILE *fp = fopen(zy_m0_eeprom, "wb+");
    fwrite(simu582_eeprom_data, 1, 32 * 1024, fp);
    if (fp) fclose(fp);
}
void EEPROM_WRITE(uint32_t StartAddr, uint8_t* Buffer, int Length)
{
    simu_eeprom();
    assert((StartAddr % 4) == 0);
    memcpy(simu582_eeprom_data + StartAddr, Buffer, Length);
    FILE* fp = fopen(zy_m0_eeprom, "wb+");
    fwrite(simu582_eeprom_data, 1, 32 * 1024, fp);
    if (fp) fclose(fp);
}
// simu flash read/write
uint8_t simu582_flash_data[448 * 1024] = { 0 };  // 448K Flash
static simu_flash(void)
{
    FILE* fp = NULL;
    static int flag = 0;
    if (!flag) {
        fp = fopen(zy_m0_flash, "rb");
        if (fp != NULL) {
            fread(simu582_flash_data, 1, 32 * 1024, fp);
        }
        else {
            fp = fopen(zy_m0_flash, "wb+");
            fwrite(simu582_flash_data, 1, 32 * 1024, fp);
        }
    }
    if (fp) {
        fclose(fp);
        flag = 1;
    }
}
void FLASH_ROM_READ(uint32_t StartAddr, uint8_t* Buffer, int Length)
{
    simu_flash();
    assert((StartAddr % 4) == 0);
    memcpy(Buffer, simu582_flash_data + StartAddr, Length);
}
void FLASH_ROM_ERASE(uint32_t StartAddr, int Length)
{
    simu_flash();
    //assert((StartAddr % 4) == 0);
    memset(simu582_flash_data + StartAddr, 0xff, Length);
    FILE* fp = fopen(zy_m0_flash, "wb+");
    fwrite(simu582_flash_data, 1, 448 * 1024, fp);
    if (fp) fclose(fp);
}
void FLASH_ROM_WRITE(uint32_t StartAddr, uint8_t* Buffer, int Length)
{
    simu_flash();
    assert(((size_t)Buffer % 4) == 0);
    memcpy(simu582_flash_data + StartAddr, Buffer, Length);
    FILE* fp = fopen(zy_m0_flash, "wb+");
    fwrite(simu582_flash_data, 1, 448 * 1024, fp);
    if (fp) fclose(fp);
}


// simu buzzor
void ThreadSimuBuzzor(void)
{
    Beep(2000, 1000);
    Sleep(3600*1000);
}
void SimuBuzzor(int isOn)
{
    static HANDLE beep_h = NULL;
    // TODO 修改为开关控制。
    if (isOn) {
        if(beep_h == NULL)
            beep_h = _beginthread(ThreadSimuBuzzor, 0, NULL);
    }
    else {
        if (beep_h) {
            Beep(0, 0);
            TerminateThread(beep_h, 0);
            CloseHandle(beep_h);
            beep_h = NULL;
        }
    }
        
}
void LowPower_Sleep(uint8_t rm)
{
    // 在这个窗口期间, 可以用来等待模拟器交换数据。
    ReleaseMutex(simu_mutex);
    // TODO 长时间模拟，需要矫正时间。
    Sleep(1000);

    WaitForSingleObject(simu_mutex, -1);
}
// 模拟打印log时输出时间
const char* GetLocalTimeStrWin32(void)
{
    static char buf[24];
    time_t t = time(NULL);
    struct tm* tt = localtime(&t);
    tt->tm_year += 1900;
    tt->tm_mon += 1;
    int ms = t % 1000;
    sprintf(buf, "%04d/%02d/%02d-%02d:%02d:%02d:%03d", tt->tm_year, tt->tm_mon, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec, ms);
    return buf;
}








// ------------------------------------------------------------------------------------------------
extern void TMR0_IRQHandler(void);
SysTick_Type _SysTick = { 0 };
SysTick_Type* SysTick = &_SysTick;
extern void RTC_IRQHandler(void);
static long long simu_rtc_sync = 0;
void CtrlInterrupt_Tick_1ms(void)
{
    //if (simu_rtc_sync++ < 1000) return;  // 延迟1000ms开始计时，主要是模拟器开头模拟的时间似乎delay严重

    //static unsigned long long simu_system_total_ms = 0;
    //simu_system_total_ms++;
    //uint32_t x = WaitForSingleObject(simu_mutex, -1);
    //SysTick_Handler();  // 模拟触发50ms tick
    //zy_timer_ms += TASK_PERIOD;
    //if(simu_system_total_ms % 50 == 0)
    SysTick->CNT+=60000;    // 主频60M
    TMR0_IRQHandler();
    //zy_timer_ms++;
    if (SysTick->CNT % (60000*1000) == 0) {   // 1s模拟触发RTC
        R8_RTC_FLAG_CTRL |= RB_RTC_TMR_FLAG;
        RTC_IRQHandler();
    }
    //ReleaseMutex(simu_mutex);
}
// PC Simulator interface ---------------------------------------------------------------------------------
HANDLE simu_main_h;         // 主任务线程句柄
HANDLE simu_mutex = NULL;   // 主任务线程互斥, 用来模拟器采样和主任务线程隔离
// simu开关机
extern int zy_main();
void ThreadMain(void)
{
    Sleep(200); // 等待模拟器初始化simu_hw结构
    //AllocConsole();
    zy_main();
}

void CtrlSwitch(int isOn)
{
    if (isOn) {
        simu_main_h = _beginthread(ThreadMain, 0, NULL);
        simu_mutex = CreateMutex(NULL, FALSE, NULL);
    }
    else {
        if (simu_mutex) CloseHandle(simu_mutex);
        if (simu_main_h) {
            TerminateThread(simu_main_h, 0);
            CloseHandle(simu_main_h);
        }
        simu_mutex = simu_main_h = 0;
    }
}

void GetMACAddress(uint8_t* buf)
{
    for (uint8_t i = 0; i < 6; i++)
        buf[i] = i;
}

void TMOS_SystemProcess(void) {}
void RTC_InitTime(uint16_t y, uint16_t mon, uint16_t d, uint16_t h, uint16_t m, uint16_t s) {};
void RTC_GetTime(uint16_t* py, uint16_t* pmon, uint16_t* pd, uint16_t* ph, uint16_t* pm, uint16_t* ps)
{
    time_t t = time(NULL);
    struct tm* tt = localtime(&t);
    *py= tt->tm_year + 1900;
    *pmon = tt->tm_mon += 1;
    *pd = tt->tm_mday;
    *ph = tt->tm_hour;
    *pm = tt->tm_min;
    *ps = tt->tm_sec;
}

static int simu_timer_start_flag = 0;
void SysTick_Config(int x) { simu_timer_start_flag = 1;  return; }
//void CALLBACK timer_handler(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
//{
//    if(simu_timer_start_flag)
//        CtrlInterrupt_Tick_50ms();
//}
void CALLBACK timer_handler(UINT uTimerID, UINT uMsg, UINT_PTR dwUser, UINT_PTR dw1, UINT_PTR dw2 )
{
    if (simu_timer_start_flag)
        CtrlInterrupt_Tick_1ms();
}

// 多媒体1ms精度定时器
#pragma comment(lib, "winmm.lib")
void BeginMTimer(void)
{
    //private static extern int timeBeginPeriod(int msec);
    //private static extern int timeEndPeriod(int msec);
    //private static extern uint timeSetEvent(int delay, int resolution, TimeProc handler, IntPtr user, int eventType);
    //private static extern int timeKillEvent(uint id);
    timeBeginPeriod(1);
    uint32_t mTimerId = timeSetEvent(1, 0, timer_handler, 0, TIME_PERIODIC);
}
// 主函数 控制台运行例子：m0.exe "\\\\.\\COM30" "2536+2616" "NULL" "NULL"
int main(int argc, char* argv[])
{
    // 设置本地化，以支持多字节字符集
    setlocale(LC_ALL, ""); 
    // 初始化模拟通讯口
    memset(zq_simu_uart_handle, 0, sizeof(zq_simu_uart_handle));
    for (int i = 0; i < (argc - 1); i++) { 
        char* com = argv[i+1];
        int len = strlen(com);
        if (strcmp(com, "NULL") == 0 || strcmp(com, "null") == 0) { // 串口n没定义, arg = "NULL"
            zq_simu_uart_handle[i].uart_port_str = NULL;
        }
        else if (com[0] == '\\' || com[0] == 'c' || com[0] == 'C') { // 串口
            zq_simu_uart_handle[i].uart_port_str = malloc(len + 1);
            strcpy(zq_simu_uart_handle[i].uart_port_str, com);
        }
        else if (com[0] >= 0x30 && com[0] <= 0x39) { // 数字，匿名管道
            char* write_str = strchr(com, '+');
            assert(write_str);
            *write_str = '\0';
            zq_simu_uart_handle[i].pipe_read = (void*)atoi(com);
            zq_simu_uart_handle[i].pipe_write = (void*)atoi(write_str+1);
        }
        else if (com[0] == 'B') { // BLE 
            assert(false); // TODO
        }
        else
        {
            assert(false);
        }
    }

    CtrlSwitch(1);

    BeginMTimer();

    WaitForSingleObject(simu_main_h, INFINITE);
    //while (1) {
    //    Sleep(1000);
    //}
    ////创建一个静态窗口，用于接收消息。窗口不具有实际的可见界面，仅用于接收消息。
    //HWND hwnd = CreateWindow("STATIC", "", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
    //UINT_PTR timerId = SetTimer(hwnd, 1, 45, timer_handler);

    //MSG msg;
    //while (GetMessage(&msg, NULL, 0, 0)) {
    //    TranslateMessage(&msg);
    //    DispatchMessage(&msg);
    //}
}

